package com.ckk.eurekaclient.util;

import com.ckk.eurekaclient.enums.EnumType;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author zhujunjun
 */
public class EnumUtil {

    private static ConcurrentHashMap<EnumCacheKey, EnumType> cacheMap = new ConcurrentHashMap<>();

    private EnumUtil() {

    }

    public static Boolean equals(EnumType et, String code) {
        if (code == null || et == null) {
            return false;
        }
        return et.getCode() == code;
    }

    public static Boolean equals(String code, EnumType et) {
        return equals(et, code);
    }

    public static <E extends EnumType> String getDesc(String code, Class<E> clz) {
        if (code == null) {
            return null;
        }
        EnumCacheKey enumCacheKey = new EnumCacheKey(code, clz);
        EnumType enumType = cacheMap.get(enumCacheKey);
        if (enumType != null) {
            return enumType.getDesc();
        }
        EnumType[] types = clz.getEnumConstants();
        for (EnumType et : types) {
            if (et.getCode().equals(code)) {
                cacheMap.put(enumCacheKey, et);
                return et.getDesc();
            }
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public static <E extends EnumType> E getEnum(String code, Class<E> clz) {
        if (code == null) {
            return null;
        }
        EnumCacheKey enumCacheKey = new EnumCacheKey(code, clz);
        EnumType enumType = cacheMap.get(enumCacheKey);
        if (enumType != null) {
            return (E) enumType;
        }
        EnumType[] types = clz.getEnumConstants();
        for (EnumType et : types) {
            if (et.getCode().equals(code)) {
                cacheMap.put(enumCacheKey, et);
                return (E) et;
            }
        }
        return null;
    }

    @AllArgsConstructor
    @Data
    private static class EnumCacheKey {
        private String code;
        private Class<?> numClz;

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            EnumCacheKey that = (EnumCacheKey) o;
            return Objects.equals(code, that.code) &&
                    Objects.equals(numClz, that.numClz);
        }

        @Override
        public int hashCode() {

            return Objects.hash(code, numClz);
        }

    }
    /**
     * 判断数值是否属于枚举类的值
     * @param clzz 枚举类 Enum
     * @param code
     * @return
     */
    public static boolean isInclude(Class<?> clzz,String code)throws Exception{

        if(clzz.isEnum()){
            Object[] enumConstants = clzz.getEnumConstants();
            Method getCode = clzz.getMethod("getCode");
            for (Object enumConstant:enumConstants){
                if (getCode.invoke(enumConstant).equals(code)) {
                    return true;
                }
            }
        }
        return false;
    }

}
